// const data = require('./test')
// const cal = require('./collegeSum')
const ruler1 = /(男子5000|男子10000|女子3000|女子5000)米/g
let score1 = [20, 16, 14, 12, 10, 8, 6, 4, 3, 2]
let score2 = [9, 7, 6, 5, 4, 3, 2, 1]
let teamScore = [18, 14, 10]

function isBrokeRecord(athlete, record) {
    if (athlete.title.indexOf(record.title) !== -1) {
        let result = String(athlete.result).localeCompare(record.record)
        return result.mode ? result > 0 : result < 0
    } else {
        return false
    }
}

function classify(events) {
    let map = new Map();
    events.forEach(singleEvent => {
        if (map.has(singleEvent.title)) {
            map.get(singleEvent.title).push(singleEvent)
        } else {
            map.set(singleEvent.title, [singleEvent])
        }
    })
    return Array.from(map.entries())
}

function sort(events) {
    events.forEach(eventGroup => {
        eventGroup.sort((e1, e2) => {
            if (e1.mode) {
                return -String(e1.result).localeCompare(String(e2.result))
            } else {
                return String(e1.result).localeCompare(String(e2.result))
            }
        })
    })
}

function mark(events) {
    events.forEach(eventGroup => {
        // TODO 团体项目赋分
        if (eventGroup[0].match(/(大众健美操|健身气功八段锦)/g) !== null) {
            eventGroup[1].forEach(event => {
                event.score = teamScore[event.ranking - 1]
            })
        }
        // 是否ruler1的项目，20、16、14、12、10、8、6、4、3、2计分
        let isRuler1 = String(eventGroup[0]).match(ruler1) !== null
        // 判断是否要减一录取
        let length = Infinity
        if (eventGroup[1].length <= (isRuler1 ? score1.length : score2.length)) {
            length = eventGroup[1].length - 1
        } else {
            length = isRuler1 ? score1.length : score2.length
        }
        eventGroup[1].forEach(event => {
            if (Number(event.ranking) / length <= 1) {
                let index = Math.trunc(Number(event.ranking) - 1 % length);
                event.score = isRuler1 ? score1[index] : score2[index]
            }
        })

    })
}

function double(events, special) {
    events.forEach(eventGroup => {
        if (eventGroup[0].match(/(接力)/g) !== null) {
            eventGroup[1].forEach(event => {
                event.score *= 2
            })
        } else if (eventGroup[0].match(/(大众健美操|健身气功八段锦)/g)) {
            if (!special) {
                eventGroup.forEach(event => {
                    event.score *= 2
                })
            }
        }
    })
}

function extraAdd(events) {
    events.forEach(eventGroup => {
        let title = String(eventGroup[0].title)
        if (title.match(/男子5000米/g) !== null) {
            eventGroup.forEach(event => {
                if (-1 === String(event.result).localeCompare("21:00:00")) {
                    event.score += 1
                }
            })
        } else if (title.match(/男子10000米/g) !== null) {
            eventGroup.forEach(event => {
                if (-1 === String(event.result).localeCompare("43:00:00")) {
                    event.score += 1
                }
            })
        } else if (title.match(/女子3000米/g) !== null) {
            eventGroup.forEach(event => {
                if (-1 === String(event.result).localeCompare("12:00:00")) {
                    event.score += 1
                }
            })
        } else if (title.match(/女子5000米/g) !== null) {
            eventGroup.forEach(event => {
                if (-1 === String(event.result).localeCompare("24:00:00")) {
                    event.score += 1
                }
            })
        }
    })
}

function recordAdd(events, records) {
    events.forEach(eventGroup => {
        eventGroup[1].forEach(event => {
            records.forEach(record => {
                if (isBrokeRecord(event, record)) {
                    // 加分
                    event.score += record.score
                }
            })
        })
    })
}

function isNumber(obj) {
    let reg = /^[0-9]+.?[0-9]*$/;
    return reg.test(obj);
}

function arePlaceCountsEqual(counts1, counts2) {
    let i = 1;
    while (true) {
        if (counts1[i] !== counts2[i]) {
            return false;
        } else if (counts1[i] === counts2[i]) {
            i++;
        }
    }
}


function placeSort(counts1, counts2) {
    let l1 = 0, l2 = 0
    let numbers1 = Object.getOwnPropertyNames(counts1).map(key => parseInt(key))
    let numbers2 = Object.getOwnPropertyNames(counts2).map(key => parseInt(key))
    numbers1 = numbers1.concat(numbers2)
    let len = numbers1.sort((a, b) => {
        return b - a
    })[0] + 1
    let rank1 = new Array(len).fill(0), rank2 = new Array(len).fill(0)
    Object.getOwnPropertyNames(counts1).forEach(key => {
        rank1[parseInt(key)] = counts1[key]
    })
    Object.getOwnPropertyNames(counts2).forEach(key => {
        rank2[parseInt(key)] = counts2[key]
    })
    return Number(rank2.join('')) - Number(rank1.join(''))
}

function calculateALl(athleteResults, recordData) {
    // Create an empty object to store the total scores for each college
    const scores = {};
    // Create an empty object to store the record-breaking count for each college
    const recordBreakCount = {};
    // Create an empty object to store the place counts for each college
    const placeCounts = {};
    // Create an empty object to store 体育学院 and 宜宾学院
    const specialArr = {}

    // trans the athleteResults form
    let tempArr = []
    athleteResults.forEach(eventGroup => {
        tempArr = tempArr.concat(eventGroup[1])
    })
    athleteResults = tempArr

    // Iterate through the array of athlete results
    athleteResults.forEach((athlete) => {
        // If the athlete has broken a record, increment their college's record-breaking count
        if (recordData !== null && recordData.length > 0) {
            recordData.forEach((record) => {
                if (isBrokeRecord(athlete, record)) {
                    recordBreakCount[athlete.college] =
                        (recordBreakCount[athlete.college] || 0) + 1;
                }
            });
        }

        // Increment the place count for the athlete's college
        placeCounts[athlete.college] = placeCounts[athlete.college] || {};
        placeCounts[athlete.college][athlete.ranking] =
            (placeCounts[athlete.college][athlete.ranking] || 0) + 1;
        // Add the athlete's score to their college's total score
        scores[athlete.college] = (scores[athlete.college] || 0) + athlete.score;
    });

    // move the key 体育学院 and 宜宾学院 to specialArr, to implement those two dose`nt take rank
    let key1, key2
    let keys = Object.getOwnPropertyNames(scores);
    keys.forEach(key => {
        if (String(key).match(/(体.*?育)|(宜.*宾)/gm) !== null) {
            specialArr[key] = scores[key]
        }
    })
    // delete the special keys in scores
    keys = Object.getOwnPropertyNames(specialArr)
    keys.forEach(key => {
        delete scores[key]
    })
    // Sort the colleges by their scores, with the highest scores first
    const sortedScores = Object.entries(scores).sort((a, b) => {
        // Compare the scores
        if (b[1] !== a[1]) {
            return b[1] - a[1];
        }
        // If the scores are equal, compare the record-breaking counts
        if (recordBreakCount[b[0]] !== recordBreakCount[a[0]]) {
            return recordBreakCount[b[0]] - recordBreakCount[a[0]];
        }
        // If the record-breaking counts are equal, compare the place counts
        return placeSort(placeCounts[a[0]], placeCounts[b[0]])
    });

    // group the college score side by side
    // Group colleges that should be ranked side by side
    let result = [[sortedScores[0]]];
    for (let i = 1; i < sortedScores.length; i++) {
        let a = sortedScores[i]
        let group = result[result.length - 1]
        if (a[1] === group[0][1] && recordBreakCount[a[0]] === recordBreakCount[group[0][0]] && arePlaceCountsEqual(placeCounts[a[0]], placeCounts[group[0][0]])) {
            group.push(a)
        } else {
            result[result.length] = [a]
        }
    }
    // mark the ranking in situation side by side
    let fakeTempRank = []
    for (let i = 0; i < sortedScores.length; i++) {
        fakeTempRank[i] = i + 1
    }
    for (let i = 0, countIndex = 0; i < result.length; i++) {
        // same group should have same rank
        // get the rank belong this group first
        let group = result[i]
        let rank = fakeTempRank[countIndex]
        group.forEach(item => {
            item[2] = rank
            countIndex++
        })
    }


    // Create an array of objects with the college name, ranking, and score
    // Return the array of results
    let tempRes = sortedScores.map(([college, score, rank], i) => ({
        college: college,
        ranking: rank,
        score: score,
    }));

    keys = Object.getOwnPropertyNames(specialArr)
    // used to store the index of special college temporary
    let tempObj = {}
    keys.forEach(specialKey => {
        let flag = false
        for (let i = 0; i < tempRes.length; i++) {
            if (specialArr[specialKey] >= tempRes[i].score) {
                // record the index of special college to be inserted
                // can`t use absolute location, in the last, the action of inserting will break the raw index, use relative location instead
                tempObj[specialKey] = tempRes[i].college
                flag = true
                break
            }
        }
        // if the special college is the last
        if (!flag) {
            tempObj[specialKey] = null
        }
    })
    // insert special college to tempRes
    keys.forEach(key => {
        // based on the relative location of college, find the index to be inserted
        let index = tempRes.length
        for (let i = 0; i < tempRes.length; i++) {
            if (tempRes[i].college === tempObj[key]) {
                index = i
                break
            }
        }

        tempRes.splice(index, 0, {
            college: key,
            ranking: index === tempRes.length ? tempRes[index - 1].ranking : tempRes[index].ranking,
            score: specialArr[key]
        })
    })
    return tempRes
}

/**
 * 计算团体成绩
 * @param events 所有的项目数组
 * @param records 所有的记录数组
 * @param special
 * @return {college: *, score: *, ranking: *}[]
 * [
 *     {
 *         "college": "计网牛",
 *         "ranking": 39,
 *         "score": 84.0931278
 *     },
 *     {
 *         "college": "法学院",
 *         "ranking": 72,
 *         "score": 67.378865462315
 *     },
 *     {
 *         "college": "体育学院",
 *         "ranking": 55,
 *         "score": 88.86316
 *     }
 * ]
 */
function calculate(events, records, special) {
    // 1. 将所有的项目按照项目名分类为数组
    let eventList = classify(events)
    // 2. 将每个项目排序
    sort(eventList)
    // 3. 按照排名赋分
    mark(eventList)
    // 4. 双分计算
    double(eventList, special)
    // 5. 时间加分
    extraAdd(eventList)
    // 6. 破纪录加分
    recordAdd(eventList, records)
    // 7. 计算团体总分
    return calculateALl(eventList, records)
}

// calculate(data, null)
module.exports = calculate;
